// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= //
//  »Project«   Talina Gaming System (TgS) (∂)
//  »File«      TgS Common - Math API [Matrix] [F] [S].i_inc
//  »Author«    Andrew Aye (EMail: mailto:andrew.aye@gmail.com, Web: http://www.andrewaye.com)
//  »Version«   4.0
// ------------------------------------------------------------------------------------------------------------------------------ //
//  Copyright: © 2002-2010, Andrew Aye.  All Rights Reserved.
//  This software is free for non-commercial use. Redistribution and use in source and binary forms, with or without modification,
//  are permitted provided that the following conditions are met: 
//    Redistributions of source code must retain this copyright notice, this list of conditions and the following disclaimers. 
//    Redistributions in binary form must reproduce this copyright notice, this list of conditions and the following
//      disclaimers in the documentation and other materials provided with the distribution. 
//  Neither the names of the copyright owner nor the names of its contributors may be used to endorse or promote products derived
//  from this software without specific prior written permission. 
//  The intellectual property rights of the algorithms used reside with Andrew Aye.  You may not use this software, in whole or
//  in part, in support of any commercial product without the express written consent of the author.
//  There is no warranty or other guarantee of fitness of this software for any purpose. It is provided solely "as is".
// =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-= //

// ---- HOMEGENEOUS 3X4 SPECIFIC FUNCTIONS -------------------------------------------------------------------------------------- //

TgINLINE TgVOID M34(F_INIT_T_04)( M34(PCU_TgMAT) ptmM0, V4(CPCU_TgVEC) ptvS0 )
{
    ptmM0->m.f11 = MKL(1.0); ptmM0->m.f12 = MKL(0.0); ptmM0->m.f13 = MKL(0.0); ptmM0->m.f14 = ptvS0->m_aData[0];
    ptmM0->m.f21 = MKL(0.0); ptmM0->m.f22 = MKL(1.0); ptmM0->m.f23 = MKL(0.0); ptmM0->m.f24 = ptvS0->m_aData[1];
    ptmM0->m.f31 = MKL(0.0); ptmM0->m.f32 = MKL(0.0); ptmM0->m.f33 = MKL(1.0); ptmM0->m.f34 = ptvS0->m_aData[2];
}


TgINLINE TgVOID M34(F_SET_T_04)( M34(PCU_TgMAT) ptmM0, V4(CPCU_TgVEC) ptvS0 )
{
    ptmM0->m.f14 = ptvS0->m_aData[0];
    ptmM0->m.f24 = ptvS0->m_aData[1];
    ptmM0->m.f34 = ptvS0->m_aData[2];
}




// ---- MIXED MATRIX CONCATENATION ---------------------------------------------------------------------------------------------- //

TgINLINE TgVOID M44(F_CAT_34_44)( M44(PCU_TgMAT) ptmM0, M34(CPCU_TgMAT) ptmM1, M44(CPCU_TgMAT) ptmM2 )
{
    TgUINT32                            ui0;

    for (ui0 = 0; ui0 < 3; ++ui0)
    {
        ptmM0->m_atyRowCol[ui0][0] =  ptmM1->m_atyRowCol[ui0][0] * ptmM2->m_atyRowCol[0][0]
                                   +  ptmM1->m_atyRowCol[ui0][1] * ptmM2->m_atyRowCol[1][0]
                                   +  ptmM1->m_atyRowCol[ui0][2] * ptmM2->m_atyRowCol[2][0]
                                   +  ptmM1->m_atyRowCol[ui0][3] * ptmM2->m_atyRowCol[3][0];
        ptmM0->m_atyRowCol[ui0][1] =  ptmM1->m_atyRowCol[ui0][0] * ptmM2->m_atyRowCol[0][1]
                                   +  ptmM1->m_atyRowCol[ui0][1] * ptmM2->m_atyRowCol[1][1]
                                   +  ptmM1->m_atyRowCol[ui0][2] * ptmM2->m_atyRowCol[2][1]
                                   +  ptmM1->m_atyRowCol[ui0][3] * ptmM2->m_atyRowCol[3][1];
        ptmM0->m_atyRowCol[ui0][2] =  ptmM1->m_atyRowCol[ui0][0] * ptmM2->m_atyRowCol[0][2]
                                   +  ptmM1->m_atyRowCol[ui0][1] * ptmM2->m_atyRowCol[1][2]
                                   +  ptmM1->m_atyRowCol[ui0][2] * ptmM2->m_atyRowCol[2][2]
                                   +  ptmM1->m_atyRowCol[ui0][3] * ptmM2->m_atyRowCol[3][2];
        ptmM0->m_atyRowCol[ui0][3] =  ptmM1->m_atyRowCol[ui0][0] * ptmM2->m_atyRowCol[0][3]
                                   +  ptmM1->m_atyRowCol[ui0][1] * ptmM2->m_atyRowCol[1][3]
                                   +  ptmM1->m_atyRowCol[ui0][2] * ptmM2->m_atyRowCol[2][3]
                                   +  ptmM1->m_atyRowCol[ui0][3] * ptmM2->m_atyRowCol[3][3];
    };

    ptmM0->m_atvRow[3] = ptmM2->m_atvRow[3];
}


TgINLINE TgVOID M44(F_CAT_44_34)( M44(PCU_TgMAT) ptmM0, M44(CPCU_TgMAT) ptmM1, M34(CPCU_TgMAT) ptmM2 )
{
    TgUINT32                            ui0;

    for (ui0 = 0; ui0 < 4; ++ui0)
    {
        ptmM0->m_atyRowCol[ui0][0] =  ptmM1->m_atyRowCol[ui0][0] * ptmM2->m_atyRowCol[0][0]
                                   +  ptmM1->m_atyRowCol[ui0][1] * ptmM2->m_atyRowCol[1][0]
                                   +  ptmM1->m_atyRowCol[ui0][2] * ptmM2->m_atyRowCol[2][0];

        ptmM0->m_atyRowCol[ui0][1] =  ptmM1->m_atyRowCol[ui0][0] * ptmM2->m_atyRowCol[0][1]
                                   +  ptmM1->m_atyRowCol[ui0][1] * ptmM2->m_atyRowCol[1][1]
                                   +  ptmM1->m_atyRowCol[ui0][2] * ptmM2->m_atyRowCol[2][1];

        ptmM0->m_atyRowCol[ui0][2] =  ptmM1->m_atyRowCol[ui0][0] * ptmM2->m_atyRowCol[0][2]
                                   +  ptmM1->m_atyRowCol[ui0][1] * ptmM2->m_atyRowCol[1][2]
                                   +  ptmM1->m_atyRowCol[ui0][2] * ptmM2->m_atyRowCol[2][2];

        ptmM0->m_atyRowCol[ui0][3] =  ptmM1->m_atyRowCol[ui0][0] * ptmM2->m_atyRowCol[0][3]
                                   +  ptmM1->m_atyRowCol[ui0][1] * ptmM2->m_atyRowCol[1][3]
                                   +  ptmM1->m_atyRowCol[ui0][2] * ptmM2->m_atyRowCol[2][3]
                                   +  ptmM1->m_atyRowCol[ui0][3];
    };
}




// ---- TRANSFORMATION ---------------------------------------------------------------------------------------------------------- //

TgINLINE V4(TgVEC) V4(F_TX_P_34)( M34(CPCU_TgMAT) ptmTX, V4(CPCU_TgVEC) ptv4 )
{
    V4(TgVEC)                           tvRet;

    tvRet.m_aData[0] = V3(F_DOT3_VV)( (V3(CPCU_TgVEC))(ptmTX->m_atvRow + 0), (V3(CPCU_TgVEC))ptv4 ) + ptmTX->m.f14;
    tvRet.m_aData[1] = V3(F_DOT3_VV)( (V3(CPCU_TgVEC))(ptmTX->m_atvRow + 1), (V3(CPCU_TgVEC))ptv4 ) + ptmTX->m.f24;
    tvRet.m_aData[2] = V3(F_DOT3_VV)( (V3(CPCU_TgVEC))(ptmTX->m_atvRow + 2), (V3(CPCU_TgVEC))ptv4 ) + ptmTX->m.f34;
    tvRet.m_aData[3] = MKL(1.0);

    return (tvRet);
}


TgINLINE V4(TgVEC) V4(F_TX_V_34)( M34(CPCU_TgMAT) ptmTX, V4(CPCU_TgVEC) ptv4 )
{
    V4(TgVEC)                           tvRet;

    tvRet.m_aData[0] = V3(F_DOT3_VV)( (V3(CPCU_TgVEC))(ptmTX->m_atvRow + 0), (V3(CPCU_TgVEC))ptv4 );
    tvRet.m_aData[1] = V3(F_DOT3_VV)( (V3(CPCU_TgVEC))(ptmTX->m_atvRow + 1), (V3(CPCU_TgVEC))ptv4 );
    tvRet.m_aData[2] = V3(F_DOT3_VV)( (V3(CPCU_TgVEC))(ptmTX->m_atvRow + 2), (V3(CPCU_TgVEC))ptv4 );
    tvRet.m_aData[3] = MKL(0.0);

    return (tvRet);
}




// ---- TRANSPOSE --------------------------------------------------------------------------------------------------------------- //

TgINLINE TgVOID M34(F_TR)( M44(PCU_TgMAT) ptmTX, M34(CPCU_TgMAT) ptmM0 )
{
    ptmTX->m_atyRowCol[0][0] = ptmM0->m_atyRowCol[0][0];
    ptmTX->m_atyRowCol[0][1] = ptmM0->m_atyRowCol[1][0];
    ptmTX->m_atyRowCol[0][2] = ptmM0->m_atyRowCol[2][0];
    ptmTX->m_atyRowCol[0][3] = MKL(0.0);

    ptmTX->m_atyRowCol[1][0] = ptmM0->m_atyRowCol[0][1];
    ptmTX->m_atyRowCol[1][1] = ptmM0->m_atyRowCol[1][1];
    ptmTX->m_atyRowCol[1][2] = ptmM0->m_atyRowCol[2][1];
    ptmTX->m_atyRowCol[1][3] = MKL(0.0);

    ptmTX->m_atyRowCol[2][0] = ptmM0->m_atyRowCol[0][2];
    ptmTX->m_atyRowCol[2][1] = ptmM0->m_atyRowCol[1][2];
    ptmTX->m_atyRowCol[2][2] = ptmM0->m_atyRowCol[2][2];
    ptmTX->m_atyRowCol[2][3] = MKL(0.0);

    ptmTX->m_atyRowCol[3][0] = ptmM0->m_atyRowCol[0][3];
    ptmTX->m_atyRowCol[3][1] = ptmM0->m_atyRowCol[1][3];
    ptmTX->m_atyRowCol[3][2] = ptmM0->m_atyRowCol[2][3];
    ptmTX->m_atyRowCol[3][3] = MKL(1.0);
}


TgINLINE TgVOID M44(F_TR)( M44(PCU_TgMAT) ptmTX, M44(CPCU_TgMAT) ptmM0 )
{
    ptmTX->m_atyRowCol[0][0] = ptmM0->m_atyRowCol[0][0];
    ptmTX->m_atyRowCol[0][1] = ptmM0->m_atyRowCol[1][0];
    ptmTX->m_atyRowCol[0][2] = ptmM0->m_atyRowCol[2][0];
    ptmTX->m_atyRowCol[0][3] = ptmM0->m_atyRowCol[3][0];

    ptmTX->m_atyRowCol[1][0] = ptmM0->m_atyRowCol[0][1];
    ptmTX->m_atyRowCol[1][1] = ptmM0->m_atyRowCol[1][1];
    ptmTX->m_atyRowCol[1][2] = ptmM0->m_atyRowCol[2][1];
    ptmTX->m_atyRowCol[1][3] = ptmM0->m_atyRowCol[3][1];

    ptmTX->m_atyRowCol[2][0] = ptmM0->m_atyRowCol[0][2];
    ptmTX->m_atyRowCol[2][1] = ptmM0->m_atyRowCol[1][2];
    ptmTX->m_atyRowCol[2][2] = ptmM0->m_atyRowCol[2][2];
    ptmTX->m_atyRowCol[2][3] = ptmM0->m_atyRowCol[3][2];

    ptmTX->m_atyRowCol[3][0] = ptmM0->m_atyRowCol[0][3];
    ptmTX->m_atyRowCol[3][1] = ptmM0->m_atyRowCol[1][3];
    ptmTX->m_atyRowCol[3][2] = ptmM0->m_atyRowCol[2][3];
    ptmTX->m_atyRowCol[3][3] = ptmM0->m_atyRowCol[3][3];
}




// -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. //
//  Scalar Function
// -.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. //

// ---- HOMEGENEOUS 3X4 SPECIFIC FUNCTIONS -------------------------------------------------------------------------------------- //

TgINLINE TgVOID M34(F_INIT_T)( M34(PCU_TgMAT) ptmM0, C_TYPE tyX, C_TYPE tyY, C_TYPE tyZ )
{
    ptmM0->m.f11 = MKL(1.0); ptmM0->m.f12 = MKL(0.0); ptmM0->m.f13 = MKL(0.0); ptmM0->m.f14 = tyX;
    ptmM0->m.f21 = MKL(0.0); ptmM0->m.f22 = MKL(1.0); ptmM0->m.f23 = MKL(0.0); ptmM0->m.f24 = tyY;
    ptmM0->m.f31 = MKL(0.0); ptmM0->m.f32 = MKL(0.0); ptmM0->m.f33 = MKL(1.0); ptmM0->m.f34 = tyZ;
}


TgINLINE TgVOID M34(F_INIT_T_03)( M34(PCU_TgMAT) ptmM0, V3(CPCU_TgVEC) ptvS0 )
{
    ptmM0->m.f11 = MKL(1.0); ptmM0->m.f12 = MKL(0.0); ptmM0->m.f13 = MKL(0.0); ptmM0->m.f14 = ptvS0->m_aData[0];
    ptmM0->m.f21 = MKL(0.0); ptmM0->m.f22 = MKL(1.0); ptmM0->m.f23 = MKL(0.0); ptmM0->m.f24 = ptvS0->m_aData[1];
    ptmM0->m.f31 = MKL(0.0); ptmM0->m.f32 = MKL(0.0); ptmM0->m.f33 = MKL(1.0); ptmM0->m.f34 = ptvS0->m_aData[2];
}


TgINLINE TgVOID M34(F_SET_T)( M34(PCU_TgMAT) ptmM0, C_TYPE tyX, C_TYPE tyY, C_TYPE tyZ )
{
    ptmM0->m.f14 = tyX;
    ptmM0->m.f24 = tyY;
    ptmM0->m.f34 = tyZ;
}


TgINLINE TgVOID M34(F_SET_T_03)( M34(PCU_TgMAT) ptmM0, V3(CPCU_TgVEC) ptvS0 )
{
    ptmM0->m.f14 = ptvS0->m_aData[0];
    ptmM0->m.f24 = ptvS0->m_aData[1];
    ptmM0->m.f34 = ptvS0->m_aData[2];
}




// ---- MIXED MATRIX ROTATION COPY ---------------------------------------------------------------------------------------------- //

TgINLINE TgVOID M33(F_INIT_ROT_34)( M33(PCU_TgMAT) ptmM0, M34(CPCU_TgMAT) ptmM1 )
{
    ptmM0->m.f11 = ptmM1->m.f11; ptmM0->m.f12 = ptmM1->m.f12; ptmM0->m.f13 = ptmM1->m.f13;
    ptmM0->m.f21 = ptmM1->m.f21; ptmM0->m.f22 = ptmM1->m.f22; ptmM0->m.f23 = ptmM1->m.f23;
    ptmM0->m.f31 = ptmM1->m.f31; ptmM0->m.f32 = ptmM1->m.f32; ptmM0->m.f33 = ptmM1->m.f33;
}


TgINLINE TgVOID M34(F_INIT_ROT_33)( M34(PCU_TgMAT) ptmM0, M33(CPCU_TgMAT) ptmM1 )
{
    ptmM0->m.f11 = ptmM1->m.f11; ptmM0->m.f12 = ptmM1->m.f12; ptmM0->m.f13 = ptmM1->m.f13; ptmM0->m.f14 = MKL(0.0);
    ptmM0->m.f21 = ptmM1->m.f21; ptmM0->m.f22 = ptmM1->m.f22; ptmM0->m.f23 = ptmM1->m.f23; ptmM0->m.f24 = MKL(0.0);
    ptmM0->m.f31 = ptmM1->m.f31; ptmM0->m.f32 = ptmM1->m.f32; ptmM0->m.f33 = ptmM1->m.f33; ptmM0->m.f34 = MKL(0.0);
}


TgINLINE TgVOID M33(F_SET_ROT_34)( M33(PCU_TgMAT) ptmM0, M34(CPCU_TgMAT) ptmM1 )
{
    ptmM0->m.f11 = ptmM1->m.f11; ptmM0->m.f12 = ptmM1->m.f12; ptmM0->m.f13 = ptmM1->m.f13;
    ptmM0->m.f21 = ptmM1->m.f21; ptmM0->m.f22 = ptmM1->m.f22; ptmM0->m.f23 = ptmM1->m.f23;
    ptmM0->m.f31 = ptmM1->m.f31; ptmM0->m.f32 = ptmM1->m.f32; ptmM0->m.f33 = ptmM1->m.f33;
}


TgINLINE TgVOID M34(F_SET_ROT_33)( M34(PCU_TgMAT) ptmM0, M33(CPCU_TgMAT) ptmM1 )
{
    ptmM0->m.f11 = ptmM1->m.f11; ptmM0->m.f12 = ptmM1->m.f12; ptmM0->m.f13 = ptmM1->m.f13;
    ptmM0->m.f21 = ptmM1->m.f21; ptmM0->m.f22 = ptmM1->m.f22; ptmM0->m.f23 = ptmM1->m.f23;
    ptmM0->m.f31 = ptmM1->m.f31; ptmM0->m.f32 = ptmM1->m.f32; ptmM0->m.f33 = ptmM1->m.f33;
}




// ---- MIXED MATRIX CONCATENATION ---------------------------------------------------------------------------------------------- //

TgINLINE TgVOID M34(F_CAT_34_33)( M34(PCU_TgMAT) ptmM0, M34(CPCU_TgMAT) ptmM1, M33(CPCU_TgMAT) ptmM2 )
{
    TgUINT32                            ui0;

    for (ui0 = 0; ui0 < 3; ++ui0)
    {
        ptmM0->m_atyRowCol[ui0][0] =  ptmM1->m_atyRowCol[ui0][0] * ptmM2->m_atyRowCol[0][0]
                                   +  ptmM1->m_atyRowCol[ui0][1] * ptmM2->m_atyRowCol[1][0]
                                   +  ptmM1->m_atyRowCol[ui0][2] * ptmM2->m_atyRowCol[2][0];
        ptmM0->m_atyRowCol[ui0][1] =  ptmM1->m_atyRowCol[ui0][0] * ptmM2->m_atyRowCol[0][1]
                                   +  ptmM1->m_atyRowCol[ui0][1] * ptmM2->m_atyRowCol[1][1]
                                   +  ptmM1->m_atyRowCol[ui0][2] * ptmM2->m_atyRowCol[2][1];
        ptmM0->m_atyRowCol[ui0][2] =  ptmM1->m_atyRowCol[ui0][0] * ptmM2->m_atyRowCol[0][2]
                                   +  ptmM1->m_atyRowCol[ui0][1] * ptmM2->m_atyRowCol[1][2]
                                   +  ptmM1->m_atyRowCol[ui0][2] * ptmM2->m_atyRowCol[2][2];
        ptmM0->m_atyRowCol[ui0][3] =  ptmM1->m_atyRowCol[ui0][3];
    };
}


TgINLINE TgVOID M44(F_CAT_33_44)( M44(PCU_TgMAT) ptmM0, M33(CPCU_TgMAT) ptmM1, M44(CPCU_TgMAT) ptmM2 )
{
    TgUINT32                            ui0;

    for (ui0 = 0; ui0 < 3; ++ui0)
    {
        ptmM0->m_atyRowCol[ui0][0] =  ptmM1->m_atyRowCol[ui0][0] * ptmM2->m_atyRowCol[0][0]
                                   +  ptmM1->m_atyRowCol[ui0][1] * ptmM2->m_atyRowCol[1][0]
                                   +  ptmM1->m_atyRowCol[ui0][2] * ptmM2->m_atyRowCol[2][0];
        ptmM0->m_atyRowCol[ui0][1] =  ptmM1->m_atyRowCol[ui0][0] * ptmM2->m_atyRowCol[0][1]
                                   +  ptmM1->m_atyRowCol[ui0][1] * ptmM2->m_atyRowCol[1][1]
                                   +  ptmM1->m_atyRowCol[ui0][2] * ptmM2->m_atyRowCol[2][1];
        ptmM0->m_atyRowCol[ui0][2] =  ptmM1->m_atyRowCol[ui0][0] * ptmM2->m_atyRowCol[0][2]
                                   +  ptmM1->m_atyRowCol[ui0][1] * ptmM2->m_atyRowCol[1][2]
                                   +  ptmM1->m_atyRowCol[ui0][2] * ptmM2->m_atyRowCol[2][2];
        ptmM0->m_atyRowCol[ui0][3] =  ptmM1->m_atyRowCol[ui0][0] * ptmM2->m_atyRowCol[0][3]
                                   +  ptmM1->m_atyRowCol[ui0][1] * ptmM2->m_atyRowCol[1][3]
                                   +  ptmM1->m_atyRowCol[ui0][2] * ptmM2->m_atyRowCol[2][3];
    };

    ptmM0->m_atvRow[3] = ptmM2->m_atvRow[3];
}


TgINLINE TgVOID M44(F_CAT_44_33)( M44(PCU_TgMAT) ptmM0, M44(CPCU_TgMAT) ptmM1, M33(CPCU_TgMAT) ptmM2 )
{
    TgUINT32                            ui0;

    for (ui0 = 0; ui0 < 4; ++ui0)
    {
        ptmM0->m_atyRowCol[ui0][0] =  ptmM1->m_atyRowCol[ui0][0] * ptmM2->m_atyRowCol[0][0]
                                   +  ptmM1->m_atyRowCol[ui0][1] * ptmM2->m_atyRowCol[1][0]
                                   +  ptmM1->m_atyRowCol[ui0][2] * ptmM2->m_atyRowCol[2][0];

        ptmM0->m_atyRowCol[ui0][1] =  ptmM1->m_atyRowCol[ui0][0] * ptmM2->m_atyRowCol[0][1]
                                   +  ptmM1->m_atyRowCol[ui0][1] * ptmM2->m_atyRowCol[1][1]
                                   +  ptmM1->m_atyRowCol[ui0][2] * ptmM2->m_atyRowCol[2][1];

        ptmM0->m_atyRowCol[ui0][2] =  ptmM1->m_atyRowCol[ui0][0] * ptmM2->m_atyRowCol[0][2]
                                   +  ptmM1->m_atyRowCol[ui0][1] * ptmM2->m_atyRowCol[1][2]
                                   +  ptmM1->m_atyRowCol[ui0][2] * ptmM2->m_atyRowCol[2][2];

        ptmM0->m_atyRowCol[ui0][3] =  ptmM1->m_atyRowCol[ui0][3];
    };
}




// ---- TRANSFORMATION ---------------------------------------------------------------------------------------------------------- //

TgINLINE V3(TgVEC) V3(F_TX_P_33)( M33(CPCU_TgMAT) ptmTX, V3(CPCU_TgVEC) ptv3 )
{
    V3(TgVEC)                           tvRet;

    tvRet.m_aData[0] = V3(F_DOT3_VV)( ptmTX->m_atvRow + 0, ptv3 );
    tvRet.m_aData[1] = V3(F_DOT3_VV)( ptmTX->m_atvRow + 1, ptv3 );
    tvRet.m_aData[2] = V3(F_DOT3_VV)( ptmTX->m_atvRow + 2, ptv3 );

    return (tvRet);
}


TgINLINE V3(TgVEC) V3(F_TX_V_33)( M33(CPCU_TgMAT) ptmTX, V3(CPCU_TgVEC) ptv3 )
{
    V3(TgVEC)                           tvRet;

    tvRet.m_aData[0] = V3(F_DOT3_VV)( ptmTX->m_atvRow + 0, ptv3 );
    tvRet.m_aData[1] = V3(F_DOT3_VV)( ptmTX->m_atvRow + 1, ptv3 );
    tvRet.m_aData[2] = V3(F_DOT3_VV)( ptmTX->m_atvRow + 2, ptv3 );

    return (tvRet);
}


TgINLINE V4(TgVEC) V4(F_TX_P_33)( M33(CPCU_TgMAT) ptmTX, V4(CPCU_TgVEC) ptv4 )
{
    V4(TgVEC)                           tvRet;

    tvRet.m_aData[0] = V3(F_DOT3_VV)( ptmTX->m_atvRow + 0, (V3(CPCU_TgVEC))ptv4 );
    tvRet.m_aData[1] = V3(F_DOT3_VV)( ptmTX->m_atvRow + 1, (V3(CPCU_TgVEC))ptv4 );
    tvRet.m_aData[2] = V3(F_DOT3_VV)( ptmTX->m_atvRow + 2, (V3(CPCU_TgVEC))ptv4 );
    tvRet.m_aData[3] = MKL(1.0);

    return (tvRet);
}


TgINLINE V4(TgVEC) V4(F_TX_V_33)( M33(CPCU_TgMAT) ptmTX, V4(CPCU_TgVEC) ptv4 )
{
    V4(TgVEC)                           tvRet;

    tvRet.m_aData[0] = V3(F_DOT3_VV)( ptmTX->m_atvRow + 0, (V3(CPCU_TgVEC))ptv4 );
    tvRet.m_aData[1] = V3(F_DOT3_VV)( ptmTX->m_atvRow + 1, (V3(CPCU_TgVEC))ptv4 );
    tvRet.m_aData[2] = V3(F_DOT3_VV)( ptmTX->m_atvRow + 2, (V3(CPCU_TgVEC))ptv4 );
    tvRet.m_aData[3] = MKL(0.0);

    return (tvRet);
}


TgINLINE V3(TgVEC) V3(F_TX_P_34)( M34(CPCU_TgMAT) ptmTX, V3(CPCU_TgVEC) ptv3 )
{
    V3(TgVEC)                           tvRet;

    tvRet.m_aData[0] = V3(F_DOT3_VV)( (V3(CPCU_TgVEC))(ptmTX->m_atvRow + 0), ptv3 ) + ptmTX->m.f14;
    tvRet.m_aData[1] = V3(F_DOT3_VV)( (V3(CPCU_TgVEC))(ptmTX->m_atvRow + 1), ptv3 ) + ptmTX->m.f24;
    tvRet.m_aData[2] = V3(F_DOT3_VV)( (V3(CPCU_TgVEC))(ptmTX->m_atvRow + 2), ptv3 ) + ptmTX->m.f34;

    return (tvRet);
}


TgINLINE V3(TgVEC) V3(F_TX_V_34)( M34(CPCU_TgMAT) ptmTX, V3(CPCU_TgVEC) ptv3 )
{
    V3(TgVEC)                           tvRet;

    tvRet.m_aData[0] = V3(F_DOT3_VV)( (V3(CPCU_TgVEC))(ptmTX->m_atvRow + 0), ptv3 );
    tvRet.m_aData[1] = V3(F_DOT3_VV)( (V3(CPCU_TgVEC))(ptmTX->m_atvRow + 1), ptv3 );
    tvRet.m_aData[2] = V3(F_DOT3_VV)( (V3(CPCU_TgVEC))(ptmTX->m_atvRow + 2), ptv3 );

    return (tvRet);
}




// ---- MATRIX LOOK AT ---------------------------------------------------------------------------------------------------------- //

TgINLINE TgVOID M34(F_LookLH_V3)( M34(PCU_TgMAT) ptmRet, V3(CPCU_TgVEC) ptvFrom, V3(CPCU_TgVEC) ptvTo, V3(CPCU_TgVEC) ptvUp )
{
    V3(TgVEC)                           tvLook, tvRight, tvCamUp;
    TYPE                                tyLength;

    // VectorNorm and Build Orthonormal Camera Axis
    tvLook = V3(F_SUB_VV)( ptvTo, ptvFrom );
    tvLook = V3(F_NORM_LEN)( &tyLength, &tvLook );
    if (F(tgCM_NR0)( tyLength ))
    {
        M34(F_CLI)( ptmRet );
        return;
    };

    tvRight = V3(F_UCX_LEN)( &tyLength, ptvUp, &tvLook );
    if (F(tgCM_NR0)( tyLength ))
    {
        M34(F_CLI)( ptmRet );
        return;
    };

    tvCamUp = V3(F_CX)( &tvLook, &tvRight );

    ptmRet->m.f11 = tvRight.m.x;  ptmRet->m.f12 = tvRight.m.y;  ptmRet->m.f13 = tvRight.m.z;  ptmRet->m.f14 = -V3(F_DOT3_VV)(&tvRight,ptvFrom);
    ptmRet->m.f21 = tvCamUp.m.x;  ptmRet->m.f22 = tvCamUp.m.y;  ptmRet->m.f23 = tvCamUp.m.z;  ptmRet->m.f24 = -V3(F_DOT3_VV)(&tvCamUp,ptvFrom);
    ptmRet->m.f31 = tvLook.m.x;   ptmRet->m.f32 = tvLook.m.y;   ptmRet->m.f33 = tvLook.m.z;   ptmRet->m.f34 = -V3(F_DOT3_VV)(&tvLook, ptvFrom);
}


TgINLINE TgVOID M34(F_LookRH_V3)( M34(PCU_TgMAT) ptmRet, V3(CPCU_TgVEC) ptvFrom, V3(CPCU_TgVEC) ptvTo, V3(CPCU_TgVEC) ptvUp )
{
    V3(TgVEC)                           tvLook, tvRight, tvCamUp;
    TYPE                                tyLength;

    // VectorNorm and Build Orthonormal Camera Axis
    tvLook = V3(F_SUB_VV)( ptvFrom, ptvTo );
    tvLook = V3(F_NORM_LEN)( &tyLength, &tvLook );
    if (F(tgCM_NR0)( tyLength ))
    {
        M34(F_CLI)( ptmRet );
        return;
    };

    tvRight = V3(F_UCX_LEN)( &tyLength, ptvUp, &tvLook );
    if (F(tgCM_NR0)( tyLength ))
    {
        M34(F_CLI)( ptmRet );
        return;
    };

    tvCamUp = V3(F_CX)( &tvLook, &tvRight );

    ptmRet->m.f11 = tvRight.m.x;  ptmRet->m.f12 = tvRight.m.y;  ptmRet->m.f13 = tvRight.m.z;  ptmRet->m.f14 = V3(F_DOT3_VV)(&tvRight,ptvFrom);
    ptmRet->m.f21 = tvCamUp.m.x;  ptmRet->m.f22 = tvCamUp.m.y;  ptmRet->m.f23 = tvCamUp.m.z;  ptmRet->m.f24 = V3(F_DOT3_VV)(&tvCamUp,ptvFrom);
    ptmRet->m.f31 = tvLook.m.x;   ptmRet->m.f32 = tvLook.m.y;   ptmRet->m.f33 = tvLook.m.z;   ptmRet->m.f34 = V3(F_DOT3_VV)(&tvLook, ptvFrom);
}


TgINLINE TgVOID M34(F_Look_V3)( M34(PCU_TgMAT) ptmRet, V3(CPCU_TgVEC) ptvFrom, V3(CPCU_TgVEC) ptvTo, V3(CPCU_TgVEC) ptvUp )
{
    M34(F_LookLH_V3)( ptmRet, ptvFrom, ptvTo, ptvUp );
}


TgINLINE TgVOID M34(F_LookLH_V4)( M34(PCU_TgMAT) ptmRet, V4(CPCU_TgVEC) ptvFrom, V4(CPCU_TgVEC) ptvTo, V4(CPCU_TgVEC) ptvUp )
{
    V4(TgVEC)                           tvLook, tvRight, tvCamUp;
    TYPE                                tyLength;

    // VectorNorm and Build Orthonormal Camera Axis
    tvLook = V4(F_SUB_VV)( ptvTo, ptvFrom );
    tvLook = V4(F_NORM_LEN)( &tyLength, &tvLook );
    if (F(tgCM_NR0)( tyLength ))
    {
        M34(F_CLI)( ptmRet );
        return;
    };

    tvRight = V4(F_UCX_LEN)( &tyLength, ptvUp, &tvLook );
    if (F(tgCM_NR0)( tyLength ))
    {
        M34(F_CLI)( ptmRet );
        return;
    };

    tvCamUp = V4(F_CX)( &tvLook, &tvRight );

    ptmRet->m.f11 = tvRight.m.x;  ptmRet->m.f12 = tvRight.m.y;  ptmRet->m.f13 = tvRight.m.z;  ptmRet->m.f14 = -V4(F_DOT_VV)(&tvRight,ptvFrom);
    ptmRet->m.f21 = tvCamUp.m.x;  ptmRet->m.f22 = tvCamUp.m.y;  ptmRet->m.f23 = tvCamUp.m.z;  ptmRet->m.f24 = -V4(F_DOT_VV)(&tvCamUp,ptvFrom);
    ptmRet->m.f31 = tvLook.m.x;   ptmRet->m.f32 = tvLook.m.y;   ptmRet->m.f33 = tvLook.m.z;   ptmRet->m.f34 = -V4(F_DOT_VV)(&tvLook, ptvFrom);
}


TgINLINE TgVOID M34(F_LookRH_V4)( M34(PCU_TgMAT) ptmRet, V4(CPCU_TgVEC) ptvFrom, V4(CPCU_TgVEC) ptvTo, V4(CPCU_TgVEC) ptvUp )
{
    V4(TgVEC)                           tvLook, tvRight, tvCamUp;
    TYPE                                tyLength;

    // VectorNorm and Build Orthonormal Camera Axis
    tvLook = V4(F_SUB_VV)( ptvFrom, ptvTo );
    tvLook = V4(F_NORM_LEN)( &tyLength, &tvLook );
    if (F(tgCM_NR0)( tyLength ))
    {
        M34(F_CLI)( ptmRet );
        return;
    };

    tvRight = V4(F_UCX_LEN)( &tyLength, ptvUp, &tvLook );
    if (F(tgCM_NR0)( tyLength ))
    {
        M34(F_CLI)( ptmRet );
        return;
    };

    tvCamUp = V4(F_CX)( &tvLook, &tvRight );

    ptmRet->m.f11 = tvRight.m.x;  ptmRet->m.f12 = tvRight.m.y;  ptmRet->m.f13 = tvRight.m.z;  ptmRet->m.f14 = V4(F_DOT_VV)(&tvRight,ptvFrom);
    ptmRet->m.f21 = tvCamUp.m.x;  ptmRet->m.f22 = tvCamUp.m.y;  ptmRet->m.f23 = tvCamUp.m.z;  ptmRet->m.f24 = V4(F_DOT_VV)(&tvCamUp,ptvFrom);
    ptmRet->m.f31 = tvLook.m.x;   ptmRet->m.f32 = tvLook.m.y;   ptmRet->m.f33 = tvLook.m.z;   ptmRet->m.f34 = V4(F_DOT_VV)(&tvLook, ptvFrom);
}


TgINLINE TgVOID M34(F_Look_V4)( M34(PCU_TgMAT) ptmRet, V4(CPCU_TgVEC) ptvFrom, V4(CPCU_TgVEC) ptvTo, V4(CPCU_TgVEC) ptvUp )
{
    M34(F_LookLH_V4)( ptmRet, ptvFrom, ptvTo, ptvUp );
}


TgINLINE TgVOID M44(F_LookLH_V3)( M44(PCU_TgMAT) ptmRet, V3(CPCU_TgVEC) ptvFrom, V3(CPCU_TgVEC) ptvTo, V3(CPCU_TgVEC) ptvUp )
{
    V3(TgVEC)                           tvLook, tvRight, tvCamUp;
    TYPE                                tyLength;

    // VectorNorm and Build Orthonormal Camera Axis
    tvLook = V3(F_SUB_VV)( ptvTo, ptvFrom );
    tvLook = V3(F_NORM_LEN)( &tyLength, &tvLook );
    if (F(tgCM_NR0)( tyLength ))
    {
        M44(F_CLI)( ptmRet );
        return;
    };

    tvRight = V3(F_UCX_LEN)( &tyLength, ptvUp, &tvLook );
    if (F(tgCM_NR0)( tyLength ))
    {
        M44(F_CLI)( ptmRet );
        return;
    };

    tvCamUp = V3(F_CX)( &tvLook, &tvRight );

    ptmRet->m.f11 = tvRight.m.x;  ptmRet->m.f12 = tvRight.m.y;  ptmRet->m.f13 = tvRight.m.z;  ptmRet->m.f14 = -V3(F_DOT3_VV)(&tvRight,ptvFrom);
    ptmRet->m.f21 = tvCamUp.m.x;  ptmRet->m.f22 = tvCamUp.m.y;  ptmRet->m.f23 = tvCamUp.m.z;  ptmRet->m.f24 = -V3(F_DOT3_VV)(&tvCamUp,ptvFrom);
    ptmRet->m.f31 = tvLook.m.x;   ptmRet->m.f32 = tvLook.m.y;   ptmRet->m.f33 = tvLook.m.z;   ptmRet->m.f44 = -V3(F_DOT3_VV)(&tvLook, ptvFrom);
    ptmRet->m.f41 = MKL(0.0);   ptmRet->m.f42 = MKL(0.0);   ptmRet->m.f43 = MKL(0.0);   ptmRet->m.f44 = MKL(1.0);
}


TgINLINE TgVOID M44(F_LookRH_V3)( M44(PCU_TgMAT) ptmRet, V3(CPCU_TgVEC) ptvFrom, V3(CPCU_TgVEC) ptvTo, V3(CPCU_TgVEC) ptvUp )
{
    V3(TgVEC)                           tvLook, tvRight, tvCamUp;
    TYPE                                tyLength;

    // VectorNorm and Build Orthonormal Camera Axis
    tvLook = V3(F_SUB_VV)( ptvFrom, ptvTo );
    tvLook = V3(F_NORM_LEN)( &tyLength, &tvLook );
    if (F(tgCM_NR0)( tyLength ))
    {
        M44(F_CLI)( ptmRet );
        return;
    };

    tvRight = V3(F_UCX_LEN)( &tyLength, ptvUp, &tvLook );
    if (F(tgCM_NR0)( tyLength ))
    {
        M44(F_CLI)( ptmRet );
        return;
    };

    tvCamUp = V3(F_CX)( &tvLook, &tvRight );

    ptmRet->m.f11 = tvRight.m.x;  ptmRet->m.f12 = tvRight.m.y;  ptmRet->m.f13 = tvRight.m.z;  ptmRet->m.f14 = V3(F_DOT3_VV)(&tvRight,ptvFrom);
    ptmRet->m.f21 = tvCamUp.m.x;  ptmRet->m.f22 = tvCamUp.m.y;  ptmRet->m.f23 = tvCamUp.m.z;  ptmRet->m.f24 = V3(F_DOT3_VV)(&tvCamUp,ptvFrom);
    ptmRet->m.f31 = tvLook.m.x;   ptmRet->m.f32 = tvLook.m.y;   ptmRet->m.f33 = tvLook.m.z;   ptmRet->m.f44 = V3(F_DOT3_VV)(&tvLook, ptvFrom);
    ptmRet->m.f41 = MKL(0.0);   ptmRet->m.f42 = MKL(0.0);   ptmRet->m.f43 = MKL(0.0);   ptmRet->m.f44 = MKL(1.0);
}


TgINLINE TgVOID M44(F_Look_V3)( M44(PCU_TgMAT) ptmRet, V3(CPCU_TgVEC) ptvFrom, V3(CPCU_TgVEC) ptvTo, V3(CPCU_TgVEC) ptvUp )
{
    M44(F_LookLH_V3)( ptmRet, ptvFrom, ptvTo, ptvUp );
}


TgINLINE TgVOID M44(F_LookLH_V4)( M44(PCU_TgMAT) ptmRet, V4(CPCU_TgVEC) ptvFrom, V4(CPCU_TgVEC) ptvTo, V4(CPCU_TgVEC) ptvUp )
{
    V4(TgVEC)                           tvLook, tvRight, tvCamUp;
    TYPE                                tyLength;

    // VectorNorm and Build Orthonormal Camera Axis
    tvLook = V4(F_SUB_VV)( ptvTo, ptvFrom );
    tvLook = V4(F_NORM_LEN)( &tyLength, &tvLook );
    if (F(tgCM_NR0)( tyLength ))
    {
        M44(F_CLI)( ptmRet );
        return;
    };

    tvRight = V4(F_UCX_LEN)( &tyLength, ptvUp, &tvLook );
    if (F(tgCM_NR0)( tyLength ))
    {
        M44(F_CLI)( ptmRet );
        return;
    };

    tvCamUp = V4(F_CX)( &tvLook, &tvRight );

    ptmRet->m.f11 = tvRight.m.x;  ptmRet->m.f12 = tvRight.m.y;  ptmRet->m.f13 = tvRight.m.z;  ptmRet->m.f14 = -V4(F_DOT_VV)(&tvRight,ptvFrom);
    ptmRet->m.f21 = tvCamUp.m.x;  ptmRet->m.f22 = tvCamUp.m.y;  ptmRet->m.f23 = tvCamUp.m.z;  ptmRet->m.f24 = -V4(F_DOT_VV)(&tvCamUp,ptvFrom);
    ptmRet->m.f31 = tvLook.m.x;   ptmRet->m.f32 = tvLook.m.y;   ptmRet->m.f33 = tvLook.m.z;   ptmRet->m.f44 = -V4(F_DOT_VV)(&tvLook, ptvFrom);
    ptmRet->m.f41 = MKL(0.0);   ptmRet->m.f42 = MKL(0.0);   ptmRet->m.f43 = MKL(0.0);   ptmRet->m.f44 = MKL(1.0);
}


TgINLINE TgVOID M44(F_LookRH_V4)( M44(PCU_TgMAT) ptmRet, V4(CPCU_TgVEC) ptvFrom, V4(CPCU_TgVEC) ptvTo, V4(CPCU_TgVEC) ptvUp )
{
    V4(TgVEC)                           tvLook, tvRight, tvCamUp;
    TYPE                                tyLength;

    // VectorNorm and Build Orthonormal Camera Axis
    tvLook = V4(F_SUB_VV)( ptvFrom, ptvTo );
    tvLook = V4(F_NORM_LEN)( &tyLength, &tvLook );
    if (F(tgCM_NR0)( tyLength ))
    {
        M44(F_CLI)( ptmRet );
        return;
    };

    tvRight = V4(F_UCX_LEN)( &tyLength, ptvUp, &tvLook );
    if (F(tgCM_NR0)( tyLength ))
    {
        M44(F_CLI)( ptmRet );
        return;
    };

    tvCamUp = V4(F_CX)( &tvLook, &tvRight );

    ptmRet->m.f11 = tvRight.m.x;  ptmRet->m.f12 = tvRight.m.y;  ptmRet->m.f13 = tvRight.m.z;  ptmRet->m.f14 = V4(F_DOT_VV)(&tvRight,ptvFrom);
    ptmRet->m.f21 = tvCamUp.m.x;  ptmRet->m.f22 = tvCamUp.m.y;  ptmRet->m.f23 = tvCamUp.m.z;  ptmRet->m.f24 = V4(F_DOT_VV)(&tvCamUp,ptvFrom);
    ptmRet->m.f31 = tvLook.m.x;   ptmRet->m.f32 = tvLook.m.y;   ptmRet->m.f33 = tvLook.m.z;   ptmRet->m.f44 = V4(F_DOT_VV)(&tvLook, ptvFrom);
    ptmRet->m.f41 = MKL(0.0);   ptmRet->m.f42 = MKL(0.0);   ptmRet->m.f43 = MKL(0.0);   ptmRet->m.f44 = MKL(1.0);
}


TgINLINE TgVOID M44(F_Look_V4)( M44(PCU_TgMAT) ptmRet, V4(CPCU_TgVEC) ptvFrom, V4(CPCU_TgVEC) ptvTo, V4(CPCU_TgVEC) ptvUp )
{
    M44(F_LookLH_V4)( ptmRet, ptvFrom, ptvTo, ptvUp );
}




// ---- MATRIX PERSPECTIVE PROJECTION ------------------------------------------------------------------------------------------- //

TgINLINE TgVOID M44(F_PProjLH)( M44(PCU_TgMAT) ptmRet, C_TYPE tyViewWidth, C_TYPE tyViewHeight, C_TYPE tyMinZ, C_TYPE tyMaxZ )
{
    C_TYPE                          tyZR = tyMaxZ - tyMinZ;
    C_TYPE                          tyFoVx = (tyMinZ+tyMinZ) / tyViewWidth;
    C_TYPE                          tyFoVy = (tyMinZ+tyMinZ) / tyViewHeight;
    C_TYPE                          tyFoVz = tyMaxZ * (tyZR > MKL(0.0) ? MKL(1.0) / tyZR : MKL(0.0));

    M44(F_CLR)( ptmRet );

    ptmRet->m.f11 = tyFoVx;
    ptmRet->m.f22 = tyFoVy;
    ptmRet->m.f33 = tyFoVz;
    ptmRet->m.f43 = MKL(1.0);
    ptmRet->m.f34 = -tyFoVz * tyMinZ;
}


TgINLINE TgVOID M44(F_PProjRH)( M44(PCU_TgMAT) ptmRet, C_TYPE tyViewWidth, C_TYPE tyViewHeight, C_TYPE tyMinZ, C_TYPE tyMaxZ )
{
    C_TYPE                          tyZR = tyMinZ - tyMaxZ;
    C_TYPE                          tyFoVx = MKL(2.0) * tyMinZ / tyViewWidth;
    C_TYPE                          tyFoVy = MKL(2.0) * tyMinZ / tyViewHeight;
    C_TYPE                          tyFoVz = tyMaxZ * (tyZR > MKL(0.0) ? MKL(1.0) / tyZR : MKL(0.0));

    M44(F_CLR)( ptmRet );

    ptmRet->m.f11 = tyFoVx;
    ptmRet->m.f22 = tyFoVy;
    ptmRet->m.f33 = tyFoVz;
    ptmRet->m.f43 = -MKL(1.0);
    ptmRet->m.f34 = tyFoVz * tyMinZ;
}


TgINLINE TgVOID M44(F_PProj)( M44(PCU_TgMAT) ptmRet, C_TYPE tyViewWidth, C_TYPE tyViewHeight, C_TYPE tyMinZ, C_TYPE tyMaxZ )
{
    M44(F_PProjLH)( ptmRet, tyViewWidth, tyViewHeight, tyMinZ, tyMaxZ );
}


TgINLINE TgVOID M44(F_PProj_OffsetLH)(
    M44(PCU_TgMAT) ptmRet, C_TYPE fRight, C_TYPE fLeft, C_TYPE fTop, C_TYPE fBottom, C_TYPE tyMinZ, C_TYPE tyMaxZ )
{
    C_TYPE                          tyXR = fRight - fLeft;
    C_TYPE                          tyYR = fTop - fBottom;
    C_TYPE                          tyZR = tyMaxZ - tyMinZ;
    C_TYPE                          tyFoVx = MKL(2.0) * tyMinZ * (tyXR > MKL(0.0) ? MKL(1.0) / tyXR : MKL(0.0));
    C_TYPE                          tyFoVy = MKL(2.0) * tyMinZ * (tyYR > MKL(0.0) ? MKL(1.0) / tyYR : MKL(0.0));
    C_TYPE                          tyFoVz = tyMaxZ * (tyZR > MKL(0.0) ? MKL(1.0) / tyZR : MKL(0.0));

    M44(F_CLR)( ptmRet );

    ptmRet->m.f11 = tyFoVx;
    ptmRet->m.f22 = tyFoVy;
    ptmRet->m.f13 = ( fLeft + fRight ) * (tyXR > MKL(0.0) ? MKL(-1.0) / tyXR : MKL(0.0));
    ptmRet->m.f23 = ( fTop + fBottom ) * (tyYR > MKL(0.0) ? MKL(-1.0) / tyYR : MKL(0.0));
    ptmRet->m.f33 = tyFoVz;
    ptmRet->m.f43 = MKL(1.0);
    ptmRet->m.f34 = -tyFoVz * tyMinZ;
}


TgINLINE TgVOID M44(F_PProj_OffsetRH)(
    M44(PCU_TgMAT) ptmRet, C_TYPE fRight, C_TYPE fLeft, C_TYPE fTop, C_TYPE fBottom, C_TYPE tyMinZ, C_TYPE tyMaxZ )
{
    C_TYPE                          tyXR = fRight - fLeft;
    C_TYPE                          tyYR = fTop - fBottom;
    C_TYPE                          tyZR = tyMaxZ - tyMinZ;
    C_TYPE                          tyFoVx = MKL(2.0) * tyMinZ * (tyXR > MKL(0.0) ? MKL(1.0) / tyXR : MKL(0.0));
    C_TYPE                          tyFoVy = MKL(2.0) * tyMinZ * (tyYR > MKL(0.0) ? MKL(1.0) / tyYR : MKL(0.0));
    C_TYPE                          tyFoVz = tyMaxZ * (tyZR > MKL(0.0) ? MKL(1.0) / tyZR : MKL(0.0));

    M44(F_CLR)( ptmRet );

    ptmRet->m.f11 = tyFoVx;
    ptmRet->m.f22 = tyFoVy;
    ptmRet->m.f13 = ( fLeft + fRight ) * (tyXR > MKL(0.0) ? MKL(1.0) / tyXR : MKL(0.0));
    ptmRet->m.f23 = ( fTop + fBottom ) * (tyYR > MKL(0.0) ? MKL(1.0) / tyYR : MKL(0.0));
    ptmRet->m.f33 = tyFoVz;
    ptmRet->m.f43 = -MKL(1.0);
    ptmRet->m.f34 = tyFoVz * tyMinZ;
}


TgINLINE TgVOID M44(F_PProj_Offset)(
    M44(PCU_TgMAT) ptmRet, C_TYPE fRight, C_TYPE fLeft, C_TYPE fTop, C_TYPE fBottom, C_TYPE tyMinZ, C_TYPE tyMaxZ )
{
    M44(F_PProj_OffsetLH)( ptmRet, fRight, fLeft, fTop, fBottom, tyMinZ, tyMaxZ );
}


TgINLINE TgVOID M44(F_PProj_FoVLH)( M44(PCU_TgMAT) ptmRet, C_TYPE tyFoV, C_TYPE tyAspect, C_TYPE tyMinZ, C_TYPE tyMaxZ )
{
    C_TYPE                          tyFoVy = MKL(1.0) / F(tgPM_TAN)( MKL(0.5) * tyFoV );
    C_TYPE                          tyFoVx = tyFoVy / tyAspect;
    C_TYPE                          tyZR = tyMaxZ - tyMinZ;
    C_TYPE                          tyFoVz = tyMaxZ * (tyZR > MKL(0.0) ? MKL(1.0) / tyZR : MKL(0.0));

    M44(F_CLR)( ptmRet );

    ptmRet->m.f11 = tyFoVx;
    ptmRet->m.f22 = tyFoVy;
    ptmRet->m.f33 = tyFoVz;
    ptmRet->m.f34 = -tyFoVz*tyMinZ;
    ptmRet->m.f43 = MKL(1.0);
}


TgINLINE TgVOID M44(F_PProj_FoVRH)( M44(PCU_TgMAT) ptmRet, C_TYPE tyFoV, C_TYPE tyAspect, C_TYPE tyMinZ, C_TYPE tyMaxZ )
{

    C_TYPE                          tyFoVy = MKL(1.0) / F(tgPM_TAN)( MKL(0.5) * tyFoV );
    C_TYPE                          tyFoVx = tyFoVy / tyAspect;
    C_TYPE                          tyZR = tyMaxZ - tyMinZ;
    C_TYPE                          tyFoVz = tyMaxZ * (tyZR > MKL(0.0) ? MKL(1.0) / tyZR : MKL(0.0));

    M44(F_CLR)( ptmRet );

    ptmRet->m.f11 = tyFoVx;
    ptmRet->m.f22 = tyFoVy;
    ptmRet->m.f33 = tyFoVz;
    ptmRet->m.f34 = -tyFoVz * tyMinZ;
    ptmRet->m.f43 = MKL(-1.0);
}


TgINLINE TgVOID M44(F_PProj_FoV)( M44(PCU_TgMAT) ptmRet, C_TYPE tyFoV, C_TYPE tyAspect, C_TYPE tyMinZ, C_TYPE tyMaxZ )
{
    M44(F_PProj_FoVLH)( ptmRet, tyFoV, tyAspect, tyMinZ, tyMaxZ );
}




// ---- MATRIX ORTHOGRAPHIC PROJECTION ------------------------------------------------------------------------------------------ //

TgINLINE TgVOID M44(F_OrthoLH)( M44(PCU_TgMAT) ptmRet, C_TYPE tyViewWidth, C_TYPE tyViewHeight, C_TYPE tyMinZ, C_TYPE tyMaxZ )
{
    if ((MKL(0.0) == tyViewWidth) || (MKL(0.0) == tyViewHeight) || (tyMinZ == tyMaxZ))
    {
        TgWARNING_MSGF( TgFALSE, TgT("%-16.16s(%-32.32s): Invalid Function Parameter\n"), TgT("Matrix API"), TgT("F_OrthoLH") );
        M44(F_CLR)( ptmRet );
    }
    else
    {
        TYPE                                tyFoVz = MKL(1.0) / ( tyMaxZ - tyMinZ );

        M44(F_CLI)( ptmRet );

        ptmRet->m.f11 = MKL(2.0) / tyViewWidth;
        ptmRet->m.f22 = MKL(2.0) / tyViewHeight;
        ptmRet->m.f33 = tyFoVz;
        ptmRet->m.f34 = -tyFoVz * tyMinZ;
        ptmRet->m.f44 = MKL(1.0);
    };
}


TgINLINE TgVOID M44(F_OrthoRH)( M44(PCU_TgMAT) ptmRet, C_TYPE tyViewWidth, C_TYPE tyViewHeight, C_TYPE tyMinZ, C_TYPE tyMaxZ )
{
    if ((MKL(0.0) == tyViewWidth) || (MKL(0.0) == tyViewHeight) || (tyMinZ == tyMaxZ))
    {
        TgWARNING_MSGF( 0, TgT("%-16.16s(%-32.32s): Invalid Function Parameter\n"), TgT("Matrix API"), TgT("F_OrthoLH") );
        M44(F_CLR)( ptmRet );
    }
    else
    {
        TYPE                                tyFoVz = MKL(1.0) / ( tyMinZ - tyMaxZ );

        M44(F_CLI)( ptmRet );

        ptmRet->m.f11 = MKL(2.0) / tyViewWidth;
        ptmRet->m.f22 = MKL(2.0) / tyViewHeight;
        ptmRet->m.f33 = tyFoVz;
        ptmRet->m.f34 = tyFoVz * tyMinZ;
        ptmRet->m.f44 = MKL(1.0);
    };
}


TgINLINE TgVOID M44(F_Ortho)( M44(PCU_TgMAT) ptmRet, C_TYPE tyViewWidth, C_TYPE tyViewHeight, C_TYPE tyMinZ, C_TYPE tyMaxZ )
{
    M44(F_OrthoLH)( ptmRet, tyViewWidth, tyViewHeight, tyMinZ, tyMaxZ );
}


TgINLINE TgVOID M44(F_Ortho_OffsetLH)(
    M44(PCU_TgMAT) ptmRet, C_TYPE fRight, C_TYPE fLeft, C_TYPE fTop, C_TYPE fBottom, C_TYPE tyMinZ, C_TYPE tyMaxZ
) {
    if ((fRight == fLeft) || (fTop == fBottom) || (tyMinZ == tyMaxZ))
    {
        TgWARNING_MSGF( 0, TgT("%-16.16s(%-32.32s): Invalid Function Parameter\n"), TgT("Matrix API"), TgT("F_OrthoLH") );
        M44(F_CLR)( ptmRet );
    }
    else
    {
        TYPE                                tyFoVx = MKL(2.0) / ( fRight - fLeft );
        TYPE                                tyFoVy = MKL(2.0) / ( fTop - fBottom );
        TYPE                                tyFoVz = MKL(1.0) / ( tyMaxZ - tyMinZ );

        M44(F_CLI)( ptmRet );

        ptmRet->m.f11 = tyFoVx;
        ptmRet->m.f22 = tyFoVy;
        ptmRet->m.f33 = tyFoVz;
        ptmRet->m.f14 = ( fLeft + fRight ) / ( fLeft - fRight );
        ptmRet->m.f24 = ( fTop + fBottom ) / ( fBottom - fTop );
        ptmRet->m.f34 = -tyFoVz * tyMinZ;
        ptmRet->m.f44 = MKL(1.0);
    };
}


TgINLINE TgVOID M44(F_Ortho_OffsetRH)(
    M44(PCU_TgMAT) ptmRet, C_TYPE fRight, C_TYPE fLeft, C_TYPE fTop, C_TYPE fBottom, C_TYPE tyMinZ, C_TYPE tyMaxZ
) {
    if ((fRight == fLeft) || (fTop == fBottom) || (tyMinZ == tyMaxZ))
    {
        TgWARNING_MSGF( 0, TgT("%-16.16s(%-32.32s): Invalid Function Parameter\n"), TgT("Matrix API"), TgT("F_OrthoLH") );
        M44(F_CLR)( ptmRet );
    }
    else
    {
        TYPE                                tyFoVx = MKL(2.0) / ( fRight - fLeft );
        TYPE                                tyFoVy = MKL(2.0) / ( fTop - fBottom );
        TYPE                                tyFoVz = MKL(1.0) / ( tyMinZ - tyMaxZ );

        M44(F_CLI)( ptmRet );

        ptmRet->m.f11 = tyFoVx;
        ptmRet->m.f22 = tyFoVy;
        ptmRet->m.f33 = tyFoVz;
        ptmRet->m.f14 = ( fLeft + fRight ) / ( fLeft - fRight );
        ptmRet->m.f24 = ( fTop + fBottom ) / ( fBottom - fTop );
        ptmRet->m.f34 = tyFoVz * tyMinZ;
        ptmRet->m.f44 = MKL(1.0);
    };
}


TgINLINE TgVOID M44(F_Ortho_Offset)(
    M44(PCU_TgMAT) ptmRet, C_TYPE fRight, C_TYPE fLeft, C_TYPE fTop, C_TYPE fBottom, C_TYPE tyMinZ, C_TYPE tyMaxZ
) {
    M44(F_Ortho_OffsetLH)( ptmRet, fRight, fLeft, fTop, fBottom, tyMinZ, tyMaxZ );
}




// ---- MATRIX ROTATION TO EULER CONVERSION ------------------------------------------------------------------------------------- //

TgINLINE TgVOID F(F_Mat2Eul_34)( PCU_TYPE ptyX, PCU_TYPE ptyY, PCU_TYPE ptyZ, M34(CPCU_TgMAT) ptmR0 )
{
    if (MKL(1.0) - ptmR0->m.f13 <= F(TgEPS))
    {
        *ptyX = F(tgPM_ATAN2)( ptmR0->m.f21, ptmR0->m.f31 );
        *ptyY = -F(TgKT_HALF_PI);
        *ptyZ = MKL(0.0);
    }
    else if (F(TgEPS) >= MKL(1.0) + ptmR0->m.f13)
    {
        *ptyX = F(tgPM_ATAN2)( ptmR0->m.f21, ptmR0->m.f31 );
        *ptyY = F(TgKT_HALF_PI);
        *ptyZ = MKL(0.0);
    }
    else
    {
        *ptyX = F(tgPM_ATAN2)( ptmR0->m.f23, ptmR0->m.f33 );
        *ptyY = F(tgPM_ASIN)( -ptmR0->m.f13 );
        *ptyZ = F(tgPM_ATAN2)( ptmR0->m.f12, ptmR0->m.f11 );
    };
}


TgINLINE TgVOID M34(F_Eul2Mat)( M34(PCU_TgMAT) ptmR0, C_TYPE tyX, C_TYPE tyY, C_TYPE tyZ )
{
    M34(F_INIT_EUL_ELEM)( ptmR0, tyX, tyY, tyZ );
}


TgINLINE TgVOID V3(F_Mat2Eul_34)( V3(PCU_TgVEC) ptvEul, M34(CPCU_TgMAT) ptmR0 )
{
    F(F_Mat2Eul_34)( &ptvEul->m.x, &ptvEul->m.y, &ptvEul->m.z, ptmR0 );
}


TgINLINE TgVOID M34(F_Eul2Mat_V3)( M34(PCU_TgMAT) ptmR0, V3(CPCU_TgVEC) ptvEul )
{
    M34(F_Eul2Mat)( ptmR0, ptvEul->m.x, ptvEul->m.y, ptvEul->m.z );
}


TgINLINE TgVOID V4(F_Mat2Eul_34)( V4(PCU_TgVEC) ptvEul, M34(CPCU_TgMAT) ptmR0 )
{
    F(F_Mat2Eul_34)( &ptvEul->m.x, &ptvEul->m.y, &ptvEul->m.z, ptmR0 );
}


TgINLINE TgVOID M34(F_Eul2Mat_V4)( M34(PCU_TgMAT) ptmR0, V4(CPCU_TgVEC) ptvEul )
{
    M34(F_Eul2Mat)( ptmR0, ptvEul->m.x, ptvEul->m.y, ptvEul->m.z );
}


TgINLINE TgVOID M34(F_Mat2Quat)( V4(PCU_TgVEC) ptqR0, M34(CPCU_TgMAT) ptmR0 )
{
    const TYPE                          tyTrace = ptmR0->m.f11 + ptmR0->m.f22 + ptmR0->m.f33;

    if (tyTrace > F(TgEPS))
    {
        const TYPE                          tySqrt = F(tgPM_SQRT)( tyTrace + MKL(1.0) );
        const TYPE                          tyScale = MKL(0.5) / tySqrt;

        ptqR0->m.x = (ptmR0->m.f32 - ptmR0->m.f23)*tyScale;
        ptqR0->m.y = (ptmR0->m.f13 - ptmR0->m.f31)*tyScale;
        ptqR0->m.z = (ptmR0->m.f21 - ptmR0->m.f12)*tyScale;
        ptqR0->m.w = MKL(0.5)*tySqrt;
    }
    else
    {
        if (ptmR0->m.f11 > ptmR0->m.f22 && ptmR0->m.f11 > ptmR0->m.f33)
        {
            const TYPE                          tyDiag = MKL(1.0) + ptmR0->m.f11 - ptmR0->m.f22 - ptmR0->m.f33;
            const TYPE                          tySqrt = F(tgPM_SQRT)( tyDiag );
            const TYPE                          tyScale = MKL(0.5) / tySqrt;

            ptqR0->m.x = MKL(0.5)*tySqrt;
            ptqR0->m.y = (ptmR0->m.f12 + ptmR0->m.f21)*tyScale;
            ptqR0->m.z = (ptmR0->m.f13 + ptmR0->m.f31)*tyScale;
            ptqR0->m.w = (ptmR0->m.f23 - ptmR0->m.f32)*tyScale;
        }
        else if (ptmR0->m.f22 > ptmR0->m.f33)
        {
            const TYPE                          tyDiag = MKL(1.0) + ptmR0->m.f22 - ptmR0->m.f11 - ptmR0->m.f33;
            const TYPE                          tySqrt = F(tgPM_SQRT)( tyDiag );
            const TYPE                          tyScale = MKL(0.5) / tySqrt;

            ptqR0->m.x = (ptmR0->m.f12 + ptmR0->m.f21)*tyScale;
            ptqR0->m.y = MKL(0.5)*tySqrt;
            ptqR0->m.z = (ptmR0->m.f23 + ptmR0->m.f32)*tyScale;
            ptqR0->m.w = (ptmR0->m.f13 - ptmR0->m.f31)*tyScale;
        }
        else
        {
            const TYPE                          tyDiag = MKL(1.0) + ptmR0->m.f33 - ptmR0->m.f11 - ptmR0->m.f22;
            const TYPE                          tySqrt = F(tgPM_SQRT)( tyDiag );
            const TYPE                          tyScale = MKL(0.5) / tySqrt;

            ptqR0->m.x = (ptmR0->m.f13 + ptmR0->m.f31)*tyScale;
            ptqR0->m.y = (ptmR0->m.f23 + ptmR0->m.f32)*tyScale;
            ptqR0->m.z = MKL(0.5)*tySqrt;
            ptqR0->m.w = (ptmR0->m.f12 - ptmR0->m.f21)*tyScale;
        };
    };
}

TgINLINE TgVOID M34(F_Quat2Mat)( M34(PCU_TgMAT) ptmM0, V4(CPCU_TgVEC) ptqR0 )
{
    M34(F_INIT_ROT)( ptmM0, ptqR0 );
}




// ---- CREATE A NON-UNIQUE BASIS FROM A SINGLE DIRECTION VECTOR ---------------------------------------------------------------- //

TgINLINE TgVOID M34(F_Set_BasisFromVector_V3)( M34(PCU_TgMAT) ptmRet, V3(CPCU_TgVEC) ptvAxis )
{
    C_TYPE tyXZ = F(tgPM_SQRT)( ptvAxis->m_aData[0]*ptvAxis->m_aData[0] + ptvAxis->m_aData[2]*ptvAxis->m_aData[2] );

    TgASSERT( (V3(F_Is_Vector_Valid)( ptvAxis )) && (F(tgCM_NR1)( V3(F_LSQ)( ptvAxis ) )) );

    if (F(tgCM_NR0)( tyXZ ))
    {
        // The parameter axis is within absolute tolerance of the standard ortho-normal definition (y-axis)
        //  It is sufficient to return the identity basis.  The identity function can not be used since the 
        // matrix being used could include other information (like translation) which should not be destroyed.

        M34(F_CLI)( ptmRet );
    }
    else
    {
        C_TYPE                          tyInvXZ = MKL(1.0) / tyXZ;

        //  Since the axis is known to be different from the standard y-axis - it is trivial to construct another
        // basis vector by taking the cross product of the two vectors.  Simplified this becomes:

        ptmRet->m.f11 = -ptvAxis->m.z * tyInvXZ;
        ptmRet->m.f12 = ptvAxis->m.x;
        ptmRet->m.f13 = -ptvAxis->m.x*ptvAxis->m.y;

        ptmRet->m.f21 = MKL(0.0);
        ptmRet->m.f22 = ptvAxis->m.y;
        ptmRet->m.f23 = ptvAxis->m.x*ptvAxis->m.x + ptvAxis->m.z*ptvAxis->m.z;

        ptmRet->m.f31 = ptvAxis->m.x * tyInvXZ;
        ptmRet->m.f32 = ptvAxis->m.z;
        ptmRet->m.f33 = -ptvAxis->m.z*ptvAxis->m.y;
    };
}


TgINLINE TgVOID M34(F_Set_BasisFromVector_V4)( M34(PCU_TgMAT) ptmRet, V4(CPCU_TgVEC) ptvAxis )
{
    C_TYPE tyXZ = F(tgPM_SQRT)( ptvAxis->m_aData[0]*ptvAxis->m_aData[0] + ptvAxis->m_aData[2]*ptvAxis->m_aData[2] );

    TgASSERT( (V4(F_Is_Vector_Valid)( ptvAxis )) && (F(tgCM_NR1)( V4(F_LSQ)( ptvAxis ) )) );

    if (F(tgCM_NR0)( tyXZ ))
    {
        // The parameter axis is within absolute tolerance of the standard ortho-normal definition (y-axis)
        //  It is sufficient to return the identity basis.  The identity function can not be used since the 
        // matrix being used could include other information (like translation) which should not be destroyed.

        M34(F_CLI)( ptmRet );
    }
    else
    {
        C_TYPE                          tyInvXZ = MKL(1.0) / tyXZ;

        //  Since the axis is known to be different from the standard y-axis - it is trivial to construct another
        // basis vector by taking the cross product of the two vectors.  Simplified this becomes:

        ptmRet->m.f11 = -ptvAxis->m.z * tyInvXZ;
        ptmRet->m.f12 = ptvAxis->m.x;
        ptmRet->m.f13 = -ptvAxis->m.x*ptvAxis->m.y;

        ptmRet->m.f21 = MKL(0.0);
        ptmRet->m.f22 = ptvAxis->m.y;
        ptmRet->m.f23 = ptvAxis->m.x*ptvAxis->m.x + ptvAxis->m.z*ptvAxis->m.z;

        ptmRet->m.f31 = ptvAxis->m.x * tyInvXZ;
        ptmRet->m.f32 = ptvAxis->m.z;
        ptmRet->m.f33 = -ptvAxis->m.z*ptvAxis->m.y;
    };
}